#include "mytcpsocket.h"
#include <QHostAddress>
#include <QThread>
#include <QJsonDocument>   // <--- 包含 JSON 相关头文件
#include <QJsonObject>
#include <QCryptographicHash> // <--- 用于计算 MD5
#include "databasemanager.h"  // <--- 包含我们的数据库管理类
#include <QJsonArray>
#include "mytcpserver.h"


MyTcpSocket::MyTcpSocket(qintptr socketDescriptor,MyTcpServer* server, QObject *parent)
    :QTcpSocket(parent),m_socketDescriptor(socketDescriptor),m_packetSize(0),m_userId(0),m_dbManager(nullptr),m_server(server)
{
    //只负责传递参数
}

MyTcpSocket::~MyTcpSocket()
{
    if(m_dbManager)
    {
        delete m_dbManager;
    }
}

void MyTcpSocket::onReadyRead()
{
    // 1. 将新收到的数据追加到我们的缓冲区中
    m_buffer.append(this->readAll());

    // 2. 循环处理，直到缓冲区中没有足够的数据构成一个完整的包
    while (true)
    {
        // A. 如果 m_packetSize 是 0，说明我们正在等待一个新的包头
        if (m_packetSize == 0)
        {
            // 检查缓冲区数据是否足够读取一个包头（4字节）
            if (m_buffer.size() < sizeof(qint32))
            {
                break; // 数据不够，退出循环，等待下一次数据到来
            }

            // 使用 QDataStream 来安全地读取 qint32
            QDataStream stream(m_buffer);
            stream.setVersion(QDataStream::Qt_6_0); // 确保版本一致
            stream >> m_packetSize; // 读取包体大小

            // 从缓冲区中移除已经读取的包头
            m_buffer.remove(0, sizeof(qint32));
        }

        // B. 如果 m_packetSize 不是 0，说明我们已经知道了包体的大小，正在等待包体数据
        if (m_packetSize > 0)
        {
            // 检查缓冲区数据是否足够构成一个完整的包体
            if (m_buffer.size() < m_packetSize)
            {
                break; // 数据不够，退出循环，等待下一次数据到来
            }

            // 数据足够，提取一个完整的包体
            QByteArray packetData = m_buffer.left(m_packetSize);
            // 从缓冲区中移除已经提取的包体
            m_buffer.remove(0, m_packetSize);

            // !! 核心处理 !! 将这个完整的数据包交给处理函数
            handlePacket(packetData);

            // 重置 m_packetSize，准备接收下一个包
            m_packetSize = 0;
        }
    }
}

void MyTcpSocket::onDisconnected()
{
    qDebug() << "Client disconnected:" << this->peerAddress().toString()
    << "on thread:" << QThread::currentThread();

    // 如果 m_userId 大于 0，说明这个 socket 是一个已登录的用户
    // 我们需要通知服务器将他从在线列表中移除
    if (this->m_userId > 0)
    {
        if (this->m_server)
        {
            this->m_server->removeOnlineUser(this->m_userId);
        }
        // 获取好友列表
        QList<QVariantMap> friends = m_dbManager->getFriends(this->m_userId);
        this->m_server->notifyFriendsOfStatusChange(this->m_userId,this->m_username,"offline",friends);
    }

    // 当客户端断开连接，我们就发射 finished 信号，触发线程和自身的销毁
    emit finished();
}

void MyTcpSocket::handlePacket(const QByteArray &packetData)
{
    QJsonParseError jsonError;
    QJsonDocument doc = QJsonDocument::fromJson(packetData, &jsonError);

    // 1. 检查 JSON 是否合法
    if (jsonError.error != QJsonParseError::NoError || !doc.isObject())
    {
        qWarning() << "JSON parse error:" << jsonError.errorString();
        return;
    }

    // 2. 将 QJsonDocument 转换为 QJsonObject
    QJsonObject jsonObj = doc.object();

    // 3. 检查是否存在 "type" 字段
    if (!jsonObj.contains("type") || !jsonObj["type"].isString())
    {
        qWarning() << "JSON does not contain 'type' field or it's not a string.";
        return;
    }

    // 4. 获取消息类型
    QString msgType = jsonObj["type"].toString();
    qDebug() << "Received message of type:" << msgType;

    if (msgType == "login_request") {
        handleLoginRequest(jsonObj);
    }
    else if (msgType == "register_request") {
        handleRegisterRequest(jsonObj);
    }
    else if (msgType == "private_message") {
        handlePrivateMessage(jsonObj);
    }
    else if(msgType == "add_friend_request")
    {
        handleFriendRequest(jsonObj);
    }
    else if (msgType == "add_friend_response")
    {
        handleFriendRequestResponse(jsonObj);
    }
    else
    {
        qWarning() << "Unknown message type:" << msgType;
    }
    return ;
}

//创建完新的线程就会调用init
void MyTcpSocket::init()
{
    // 在这个函数开头创建 DatabaseManager 实例
    // 因为 init() 是在新线程中执行的，所以 dbManager 及其数据库连接
    // 也就自然地属于这个新线程了。
    this->m_dbManager = new DatabaseManager();

    // 关键：将套接字描述符设置给 QTcpSocket
    // 这个函数现在会在新的工作线程中被调用
    if (!this->setSocketDescriptor(m_socketDescriptor))
    {
        qWarning() << "Failed to set socket descriptor.";
        emit finished(); // 如果失败，直接结束
        return;
    }

    // 连接内置的信号到我们自己的槽函数
    connect(this, &MyTcpSocket::readyRead, this, &MyTcpSocket::onReadyRead);
    connect(this, &MyTcpSocket::disconnected, this, &MyTcpSocket::onDisconnected);

    // 打印一条日志，看看是哪个客户端连接进来了，以及它在哪个线程
    qDebug() << "Client connected:" << this->peerAddress().toString()
             << "on thread:" << QThread::currentThread();
}

void MyTcpSocket::handleLoginRequest(const QJsonObject &jsonObj)
{
    QString username = jsonObj["username"].toString();
    QString password = jsonObj["password"].toString(); // 客户端应发来MD5哈希

    // 调用数据库进行验证
    int userId = m_dbManager->validateUser(username, password);

    QJsonObject response;
    response["type"] = "login_response";

    if (userId > 0)// 验证成功 (假设 user_id > 0)
    {

        // 1. "记住"自己的用户ID
        this->m_userId = userId;
        this->m_username = username;
        // 2. 向服务器“登记”，告诉服务器“我这个连接现在代表 user_id”
        //    我们需要获取到 MyTcpServer 的实例。
        //    QTcpSocket 有一个 server() 方法可以获取到它的父 QTcpServer*

        if (this->m_server)
        {
            this->m_server->addOnlineUser(this->m_userId, this);
        }

        response["success"] = true;
        response["user_id"] = userId;
        response["username"] = username;

        // 获取并添加好友列表
        QList<QVariantMap> friends = m_dbManager->getFriends(userId);
        QJsonArray friendsArray;
        for (const auto& friendData : friends) {
            // friendsArray.append(QJsonObject::fromVariantMap(friendData));

            QJsonObject friendObj = QJsonObject::fromVariantMap(friendData);
            // --- 关键修改：在这里添加在线状态 ---
            int friendId = friendData["user_id"].toInt();
            // 从服务器的在线用户列表里查询该好友是否在线
            if (this->m_server->isUserOnline(friendId)) { // 假设 server 有 isUserOnline 方法
                friendObj["status"] = "online";
            } else {
                friendObj["status"] = "offline";
            }
            // --- 修改结束 ---

            friendsArray.append(friendObj);

        }

        if (this->m_server)
        {
            // 通知我自己的好友们，“我”上线了
            this->m_server->notifyFriendsOfStatusChange(this->m_userId, this->m_username, "online",friends);
        }
        response["friends"] = friendsArray;

    }
    else
    {
        response["success"] = false;
        response["error_message"] = "用户名或密码错误";
    }

    sendJsonResponse(response);
}

void MyTcpSocket::handleRegisterRequest(const QJsonObject &jsonObj)
{
    QString username = jsonObj["username"].toString();
    QString password = jsonObj["password"].toString();

    // 计算密码的MD5哈希值 (我们在这里计算，因为服务器不应该信任客户端发来的任何哈希)
    // **修正：根据我们的协议，客户端计算MD5，服务器直接存储**
    // QString passwordHash = QString(QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex());

    // 调用数据库进行注册
     bool success = m_dbManager->registerUser(username, password);

    // 构建响应 JSON
    QJsonObject response;
    response["type"] = "register_response";
    response["success"] = success;

    if (!success) {
        response["error_message"] = "用户名已被占用";
    }

    // 发送响应
    sendJsonResponse(response);
}

void MyTcpSocket::sendJsonResponse(const QJsonObject &jsonObj)
{
    // 1. 将 JSON 对象转换为 QByteArray
    QByteArray jsonData = QJsonDocument(jsonObj).toJson(QJsonDocument::Compact);


    // 2. 按照我们的协议封包：[长度-内容]
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_0);
    out << (qint32)jsonData.size(); // 写入包头（包体长度）
    out.writeRawData(jsonData.constData(), jsonData.size()); // 写入包体

    // 3. 发送数据
    this->write(block);
    this->flush(); // 确保数据立即发送
}

void MyTcpSocket::handlePrivateMessage(const QJsonObject &jsonObj)
{
    int toId = jsonObj["to_id"].toInt();

    // 从服务器的在线用户列表中找到接收方的 socket
    if (!this->m_server) return;

    MyTcpSocket* receiverSocket = this->m_server->findOnlineUser(toId);

    if (receiverSocket) {
        // 如果对方在线，直接转发
        receiverSocket->sendJsonResponse(jsonObj);
        qDebug() << "Message forwarded to user" << toId;
    } else {
        // 如果对方不在线，可以先存为离线消息
        qDebug() << "User" << toId << "is offline. Message stored.";
        // (离线消息功能后续实现)
    }
}

int MyTcpSocket::userId() const
{
    return m_userId;
}

void MyTcpSocket::handleFriendRequest(const QJsonObject &jsonObj)
{
    /*
a. 查询数据库，验证请求的合法性（用户是否存在，是否已是好友等）。
b. 如果合法，找到目标好友的 MyTcpSocket 连接。
c. 如果目标好友在线，就构建 "add_friend_notification" 消息并转发给他。
    */
    // 1. 解析请求
    int fromId = jsonObj["from_id"].toInt();
    QString toUsername = jsonObj["to_username"].toString();
    QString message = jsonObj["message"].toString();


    // 2. 调用数据库进行合法性校验
    int toId = this->m_dbManager->getUserId(toUsername);

    // --- 各种失败情况的判断 ---
    if (toId == -1) {
        qWarning() << "Add friend failed: User" << toUsername << "does not exist.";
        // (进阶：可以向发起方返回一个“用户不存在”的错误提示)
        return;
    }
    if (toId == fromId) {
        qWarning() << "Add friend failed: Cannot add yourself.";
        // (进阶：可以向发起方返回一个“不能加自己为好友”的错误提示)
        return;
    }
    if (this->m_dbManager->areAlreadyFriends(fromId, toId)) {
        qWarning() << "Add friend failed: Already friends.";
        // (进阶：可以向发起方返回一个“你们已经是好友了”的错误提示)
        return;
    }

    // 3. 获取 MyTcpServer 实例，以查找目标用户是否在线

    if (!this->m_server)
    {
        qWarning() << "Cannot get server instance in handleAddFriendRequest.";
        return;
    }

    // 4. 检查目标用户是否在线
    if (this->m_server->isUserOnline(toId))
    {
        // 5. 如果在线，构建通知并转发
        QJsonObject notification;
        notification["type"] = "add_friend_notification";
        notification["from_id"] = fromId;
        // 我们需要发起方的用户名，但当前 jsonObj 里没有。需要从数据库查。
        notification["from_username"] = this->m_dbManager->getUsername(fromId); // 假设dbManager有此函数
        notification["message"] = message;

        // 获取目标用户的 socket 并发送
        MyTcpSocket* targetSocket = this->m_server->findOnlineUser(toId); // 假设 server 有此函数
        if (targetSocket)
        {
            targetSocket->sendJsonResponse(notification);
            qDebug() << "Sent add_friend_notification from" << fromId << "to" << toId;
        }
    }
    else
    {
        // 6. (进阶) 如果不在线，可以将申请存入数据库的 "FriendRequests" 表中
        qDebug() << "Target user" << toId << "is offline. Friend request will be delivered later.";
    }


    return ;
}

void MyTcpSocket::handleFriendRequestResponse(const QJsonObject &jsonObj)
{
    // 1. 解析响应数据
    int fromId = jsonObj["from_id"].toInt(); // 申请人 A 的 ID
    int toId = jsonObj["to_id"].toInt();     // 响应人 B 的 ID (就是当前这个socket的用户)
    bool accepted = jsonObj["accepted"].toBool();

    // 2. 如果对方拒绝了，我们按简化逻辑，什么都不做
    if (!accepted)
    {
        qDebug() << "User" << toId << "rejected friend request from" << fromId;
        return;
    }

    // 3. 如果对方同意了
    // a. 在数据库中添加好友关系
    if (m_dbManager->addFriend(fromId, toId) == false)
    {
        // 如果因为某些原因（比如数据库错误）添加失败，也直接返回
        qWarning() << "Database: Failed to add friend relationship between" << fromId << "and" << toId;
        return;
    }
    qDebug() << "Database: Added friend relationship between" << fromId << "and" << toId;

    // b. 获取 Server 实例，用于查找在线用户

    if (!this->m_server)
    {
        return;
    }

    // --- c. 通知申请人 A ---
    // 获取申请人 A 的用户名等信息
    QVariantMap applicantInfo = this->m_dbManager->getUserInfo(fromId); // 假设dbManager有此函数

    // 构建成功结果的 JSON 消息
    QJsonObject resultToApplicant;
    resultToApplicant["type"] = "add_friend_result";
    resultToApplicant["success"] = true;
    resultToApplicant["friend_id"] = toId; // 告诉 A，你新加的好友是 B
    resultToApplicant["friend_username"] = this->m_dbManager->getUsername(toId);

    // 查找 A 的 socket 并发送
    MyTcpSocket* applicantSocket = this->m_server->findOnlineUser(fromId);
    if (applicantSocket)
    {
        applicantSocket->sendJsonResponse(resultToApplicant);
        qDebug() << "Sent add_friend_result(success) to user" << fromId;
    }
    else
    {
        qDebug() << "user:" << toId << "offline,can not send.please resend friendApplication.";
        return ;            //避免B加上了A的好友，而A没有加上B的好友
    }
    // --- d. (重要补充) 通知响应人 B (也就是自己) ---
    // 我们也需要让 B 的好友列表刷新，把 A 显示出来
    // 构建一个类似的结果消息，只是好友信息是 A
    QJsonObject resultToResponder;
    resultToResponder["type"] = "add_friend_result";
    resultToResponder["success"] = true;
    resultToResponder["friend_id"] = fromId; // 告诉 B，你新加的好友是 A
    resultToResponder["friend_username"] = applicantInfo["username"].toString();

    // 直接通过当前的 this 指针发送给自己
    this->sendJsonResponse(resultToResponder);
    qDebug() << "Sent add_friend_result(success) to user" << toId;
}


